/*
 * forward_adapter_with_comments.cpp
 *
 * 说明：
 *   本示例演示“正向适配”模式：在保持底层回调实现不变的前提下，
 *   向外导出一个同时兼容“传统回调”和“协程 co_await”的异步接口。
 *
 *   为了避免异步操作过程中局部对象生命周期提前结束，
 *   我们在 legacy_consumer 中使用 std::enable_shared_from_this
 *   构建一个小型 Session，让定时器等资源在回调触发前保持有效。
 *
 * 构建方式（需要启用 C++20，并链接 Boost.System 与 pthread）：
 *   g++ -std=c++20 -O2 forward_adapter_with_comments.cpp -o forward_adapter \
 *       -lboost_system -lpthread
 *   ./forward_adapter
 */

#include <boost/asio.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <chrono>
#include <iostream>
#include <memory>
#include <string>

namespace asio = boost::asio;
using asio::awaitable;
using asio::co_spawn;
using asio::detached;
using asio::use_awaitable;
using boost::system::error_code;
using namespace std::chrono_literals;

// -----------------------------------------------------------------------------
// 底层遗留实现：只提供回调形式的非阻塞接口。
// 说明：在现实项目中，这可能来自旧库或第三方组件，暂时无法改动。
// -----------------------------------------------------------------------------
template <class CompletionHandler>
void legacy_fetch_user(const std::string& user_id,
                       asio::steady_timer& timer,
                       CompletionHandler&& handler) {
    // 1) 设置定时器超时时间，模拟网络 I/O 延迟。
    timer.expires_after(200ms);

    // 2) 以异步方式等待定时器到期，完成时调用 handler。
    //    注意：handler 会被包装进 lambda，确保传入的 CompletionHandler 能继续使用。
    timer.async_wait(
        [handler = std::forward<CompletionHandler>(handler), user_id](const error_code& ec) mutable {
            if (ec) {
                // 如果等待过程中被取消或发生错误（例如对象提前销毁），返回错误码并传空字符串。
                handler(ec, std::string{});
                return;
            }

            // 正常完成：回调接收一个伪造的“用户档案”字符串。
            handler({}, "profile-data-for:" + user_id);
        });
}

// -----------------------------------------------------------------------------
// 适配器接口：对外暴露 async_fetch_user_profile，支持回调或协程 co_await。
//
// CompletionToken 可以是：
//   - 一个回调函数（传统风格）
//   - boost::asio::use_future（获得 std::future）
//   - boost::asio::use_awaitable（协程 co_await 使用）
//   - 以及自定义 token（例如 stackless 协程、sync completion 等）
// -----------------------------------------------------------------------------
template <class CompletionToken>
auto async_fetch_user_profile(const std::string& user_id,
                              asio::steady_timer& timer,
                              CompletionToken&& token) {
    // async_initiate 将“初始化逻辑”和“CompletionToken”绑定在一起，
    // 以完成回调到协程、future 等不同异步模式之间的转换。
    return asio::async_initiate<CompletionToken,
                                void(error_code, std::string)>(
        // initiation：真正触发底层操作的函数对象。
        [&timer, user_id](auto handler) mutable {
            // handler 的实际类型由 CompletionToken 推断，可能是回调，也可能是协程的 promise。
            legacy_fetch_user(user_id, timer, std::move(handler));
        },
        token);
}

// -----------------------------------------------------------------------------
// 旧调用方：仍旧以回调模式使用异步接口。
// 关键点：timer 需要活得比异步操作久，因此使用 Session 来管理生命周期。
// -----------------------------------------------------------------------------
void legacy_consumer(asio::io_context& io) {
    // Session 持有定时器，并通过 shared_ptr 保证在回调执行前不被销毁。
    struct Session : std::enable_shared_from_this<Session> {
        asio::steady_timer timer;

        explicit Session(asio::io_context& io_ctx)
            : timer(io_ctx) {}

        void start() {
            std::cout << "[legacy] request profile for alice...\n";

            // 传入 shared_from_this() 以延长 Session 生命周期，直到回调触发。
            async_fetch_user_profile("alice", timer,
                                     [self = shared_from_this()](const error_code& ec, std::string profile) {
                                         if (ec) {
                                             std::cerr << "[legacy] error: " << ec.message() << "\n";
                                             return;
                                         }
                                         std::cout << "[legacy] got profile: " << profile << "\n";
                                     });
        }
    };

    // Start 会立刻发起异步请求，但真正的回调将在事件循环运行时触发。
    std::make_shared<Session>(io)->start();
}

// -----------------------------------------------------------------------------
// 新调用方：直接在协程中 co_await 适配后的接口。
// 优点：
//   - 控制流接近同步写法。
//   - 异常与错误处理更直观。
//   - 易于组合和测试。
// -----------------------------------------------------------------------------
awaitable<void> modern_consumer() {
    // 获取当前协程关联的 executor，用于构造与协程生命周期相同的定时器。
    auto executor = co_await asio::this_coro::executor;
    asio::steady_timer timer(executor);

    // redirect_error + use_awaitable：将协程中的异常转换为 error_code 返回，而不是抛出异常。
    error_code ec;
    std::string profile =
        co_await async_fetch_user_profile("bob", timer,
                                          asio::redirect_error(use_awaitable, ec));

    if (ec) {
        std::cerr << "[modern] error: " << ec.message() << "\n";
        co_return;
    }
    std::cout << "[modern] got profile: " << profile << "\n";
    co_return;
}

// -----------------------------------------------------------------------------
// 主函数：同时演示旧接口与新接口的调用。
// -----------------------------------------------------------------------------
int main() {
    asio::io_context io;

    legacy_consumer(io);                        // 旧代码沿用回调路径
    co_spawn(io, modern_consumer(), detached);  // 新代码使用协程路径

    io.run();
    return 0;
}